package com.dhcc.bpm.alarm.utils;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.yaml.snakeyaml.Yaml;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.util.*;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import static org.springframework.util.StreamUtils.BUFFER_SIZE;

@Slf4j
public class BaseUtils {
    private static Logger logger = LoggerFactory.getLogger(BaseUtils.class);
    /**
     * 顺序号
     */
    public static Integer INDEX_NO = 0;
    public static String SEED_DATE = "";

    public static final MySimpleDateFormat sdf = new MySimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    public static final MySimpleDateFormat YMD = new MySimpleDateFormat("yyyy-MM-dd");
    public static final MySimpleDateFormat YMD_CN = new MySimpleDateFormat("yyyy年MM月dd日");
    public static MySimpleDateFormat Times = new MySimpleDateFormat("HH:mm:ss");

    public static MySimpleDateFormat Y2DTIME_FORMAT = new MySimpleDateFormat(
            "yyyy-MM-dd HH:mm:ss");

    public static MySimpleDateFormat Y2CH_FORMAT = new MySimpleDateFormat(
            "yyyy年MM月dd日 HH时mm分ss秒");

    public static MySimpleDateFormat Y2NO_FORMAT = new MySimpleDateFormat(
            "yyyyMMddHHmmss");

    public static MySimpleDateFormat Y2D_FORMAT = new MySimpleDateFormat("yyyyMMdd");

    public static MySimpleDateFormat Y2T_FORMAT = new MySimpleDateFormat("HHmmss");

    public static MySimpleDateFormat YMD_FORMAT = new MySimpleDateFormat(
            "yyyy-MM-dd");

    public static MySimpleDateFormat Y2NO_Mill_FORMAT = new MySimpleDateFormat(
            "yyyyMMddHHmmssSSS");
    public static MySimpleDateFormat Y2NO_Minute_FORMAT = new MySimpleDateFormat(
            "yyyyMMddHHmm");

    public static final MySimpleDateFormat Y2SPECIAL_FORMAT = new MySimpleDateFormat("yyyy.MM.dd");

    public static String getSystemDateOfString() {
        Calendar calendar = Calendar.getInstance();
        return sdf.format(calendar.getTime());
    }
    public static String getSystemDateStringY2NO() {
        Calendar calendar = Calendar.getInstance();
        return Y2NO_FORMAT.format(calendar.getTime());
    }

    public static Date getSystemDate() {
        Calendar calendar = Calendar.getInstance();
        return calendar.getTime();
    }
    public static String getSystemTimes() {
        Calendar calendar = Calendar.getInstance();
        return Times.format(calendar.getTime());
    }

    public static String getSystemDateString() {
        Calendar calendar = Calendar.getInstance();
        return YMD_FORMAT.format(calendar.getTime());
    }

    public static String getSystemDateStringY2NOMill() {
        Calendar calendar = Calendar.getInstance();
        return Y2NO_Mill_FORMAT.format(calendar.getTime());
    }
    public static String getSystemDateStringY2NOMinute() {
        Calendar calendar = Calendar.getInstance();
        return Y2NO_Minute_FORMAT.format(calendar.getTime());
    }

    public static Date getShortDate(String date) {
        try {
            return YMD.parse(date);
        } catch (ParseException e) {
            System.out.print("日期格式不正确!");
        }
        return null;
    }

    public static Date getDate(String date) {
        try {
            return sdf.parse(date);
        } catch (ParseException e) {
            System.out.print("日期格式不正确!");
        }
        return getSystemDate();
    }

    /**
     * 比较两个时间的前后
     *
     * @param DATE1
     * @param DATE2
     * @return 1 DATE1 在 DATE2 之前
     */
    public static int compare_date(String DATE1, String DATE2) {

        try {
            Date dt1 = Y2SPECIAL_FORMAT.parse(DATE1);
            Date dt2 = Y2SPECIAL_FORMAT.parse(DATE2);
            if (dt1.getTime() > dt2.getTime()) {
                return 1;
            } else if (dt1.getTime() < dt2.getTime()) {
                return -1;
            } else {
                return 0;
            }
        } catch (Exception exception) {
            exception.printStackTrace();
        }
        return 0;
    }

    /*
     * 将时间转换为时间戳
     * @param s   yyyy-MM-dd HH:mm:ss
     */
    public static String dateToStamp(String s) throws ParseException {
        String res;
        Date date = sdf.parse(s);
        long ts = date.getTime();
        res = String.valueOf(ts);
        return res;
    }

    /*
     * 将时间戳转换为时间
     * @param s   yyyy-MM-dd HH:mm:ss
     */
    public static String stampToDate(String s) {
        String res;

        long lt = new Long(s);
        Date date = new Date(lt);
        res = sdf.format(date);
        return res;
    }

    /**
     * 获取两个日期之间的所有日期
     *
     * @param startTime 开始日期
     * @param endTime   结束日期
     * @return
     */
    public static List<String> getDays(String startTime, String endTime) {

        // 返回的日期集合
        List<String> days = new ArrayList<String>();
        try {
            Date start = YMD.parse(startTime);
            Date end = YMD.parse(endTime);

            Calendar tempStart = Calendar.getInstance();
            tempStart.setTime(start);

            Calendar tempEnd = Calendar.getInstance();
            tempEnd.setTime(end);
            tempEnd.add(Calendar.DATE, +1);// 日期加1(包含结束)
            while (tempStart.before(tempEnd)) {
                days.add(YMD.format(tempStart.getTime()));
                tempStart.add(Calendar.DAY_OF_YEAR, 1);
            }

        } catch (ParseException e) {
            e.printStackTrace();
        }

        return days;
    }


    public static Long storeSizeToKB(String size) {
        String str = size.toUpperCase().replaceAll("[0-9]", "").substring(0, 1);
        String value = size.toUpperCase().replaceAll("[A-Z]", "");
        Double number = Double.parseDouble(value);
        switch (str) {
            case "K":
                break;
            case "M":
                number *= 1024;
                break;
            case "G":
                number *= 1024 * 1024;
                break;
            case "T":
                number *= 1024 * 1024;
                break;

        }
        return number.longValue();
    }

    public static Long storeSizeToKB2(String size) {
        String str = size.toUpperCase().substring(size.length() - 2, size.length() - 1);
        String value = size.toUpperCase().substring(0, size.length() - 2);
        Double number = Double.parseDouble(value);
        switch (str) {
            case "K":
                break;
            case "M":
                number *= 1024;
                break;
            case "G":
                number *= 1024 * 1024;
                break;
            case "T":
                number *= 1024 * 1024;
                break;

        }
        return number.longValue();
    }

    public static String storeKbToSize(Long number) {

        Double db = (double) number;
        int i = 0;
        while (number / 1024 >= 1) {
            System.out.println(db / 1024);
            double dou = (number % 1024) / 1024.0;
            number = number / 1024;
            db = number + dou;
            i++;

        }
        String str = null;
        switch (i) {
            case 0:
                str = "K";
                break;
            case 1:
                str = "M";
                break;
            case 2:
                str = "G";
                break;
            case 3:
                str = "T";
                break;

        }
        DecimalFormat df = new DecimalFormat("#.00");
        return Double.parseDouble(df.format(db)) + str;
    }

    public static String getMD5(String source) {
        byte[] sourceByte = source.getBytes();
        String s = null;
        char hexDigits[] = { // 用来将字节转换成 16 进制表示的字符
                '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
        try {
            java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
            md.update(sourceByte);
            byte tmp[] = md.digest(); // MD5 的计算结果是一个 128 位的长整数，
            // 用字节表示就是 16 个字节
            char str[] = new char[16 * 2]; // 每个字节用 16 进制表示的话，使用两个字符，
            // 所以表示成 16 进制需要 32 个字符
            int k = 0; // 表示转换结果中对应的字符位置
            for (int i = 0; i < 16; i++) { // 从第一个字节开始，对 MD5 的每一个字节
                // 转换成 16 进制字符的转换
                byte byte0 = tmp[i]; // 取第 i 个字节
                str[k++] = hexDigits[byte0 >>> 4 & 0xf]; // 取字节中高 4 位的数字转换,
                // >>> 为逻辑右移，将符号位一起右移
                str[k++] = hexDigits[byte0 & 0xf]; // 取字节中低 4 位的数字转换
            }
            s = new String(str); // 换后的结果转换为字符串

        } catch (Exception e) {
            e.printStackTrace();
        }
        return s.toUpperCase();
    }

    public static String codeToLower(String code) {
        String co = code;
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < co.length(); i++) {
            char c = co.charAt(i);
            if (c >= 65 && c <= 90) {
                c += 32;
                sb.append(c);
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    public static String getUserDir(String username) {
        if (username.equals("root")) {
            return "/root";
        } else {
            return "/home/" + username;
        }
    }

    public static String fullPath(String path, String fileName) {
        if (path.endsWith("/")) {
            return path + fileName;
        } else {
            return path + "/" + fileName;
        }
    }

    public static String nextPath(String fileName) {
        return fileName.replaceFirst(".jar", "-jar") + "/old-jar";
    }


    public static JSONObject chmodFile(String username, String ls, String[] groups) {
        JSONObject json = new JSONObject();
        String[] lss = ls.split("\\s+");
        json.put("isRead", false);
        json.put("isWrite", false);
        json.put("contents", lss[8]);
        if (lss[0].startsWith("-")) {
            json.put("isLeaf", true);
        } else {
            json.put("isLeaf", false);
        }
        String user = lss[2];
        String group = lss[3];
        if ("root".equals(username)) {
            json.put("isRead", true);
            json.put("isWrite", true);
            return json;
        }
        if (user.endsWith(username)) {
            //文件所属用户 是当前用户
            if (lss[0].substring(1, 2).endsWith("r")) {
                json.put("isRead", true);
            }
            if (lss[0].substring(2, 3).endsWith("w")) {
                json.put("isWrite", true);
            }
        } else {
            //文件所属用户不是当前用户查看是否在当前组
            boolean flag = true;
            for (String gr : groups) {
                if (group.equals(gr)) {
                    if (lss[0].substring(4, 5).endsWith("r")) {
                        flag = false;
                        json.put("isRead", true);
                    }
                    if (lss[0].substring(5, 6).endsWith("w")) {
                        flag = false;
                        json.put("isWrite", true);
                    }
                }
            }
            //flag = true ,说明文件所属组，不是当前用户组
            if (flag) {
                if (lss[0].substring(7, 8).endsWith("r")) {
                    json.put("isRead", true);
                }
                if (lss[0].substring(8, 9).endsWith("w")) {
                    json.put("isWrite", true);
                }
            }


        }
        return json;
    }

    public static Map<String, Object> getMapArgs(String yml) {
        Yaml yaml = new Yaml();
        Map<String, Object> application = (Map) yaml.load(yml);
        Map<String, Object> map = new HashMap<>();
        getMapArgs(application, "", map);
        return map;
    }

    public static Boolean isYml(String yml) {
        try {
            Yaml yaml = new Yaml();
            Map<String, Object> application = (Map) yaml.load(yml);
        }catch (Exception e){
            return false;
        }
        return true;
    }

    public static boolean isInteger(String str) {
        Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*$");
        return pattern.matcher(str).matches();
    }

    //递归找出jar的配置项
    private static void getMapArgs(Map<String, Object> map, String keys, Map<String, Object> maps) {
        for (String key : map.keySet()) {
            Object value = map.get(key);
            if (!StringUtils.isBlank(keys)) {
                key = keys + "." + key;
            }
            if (value == null) {
                continue;
            }
            if (LinkedHashMap.class.getName().equals(value.getClass().getName()))
                getMapArgs((Map<String, Object>) value, key, maps);
            else {
                maps.put(key, value);
            }

        }
    }


    public static String keyValueToYml(Map<String, Object> map) {
        Yaml yaml = new Yaml();
        Map<Integer, Object> n = new HashMap<>();
        for (int k = 0; k < Integer.MAX_VALUE; k++) {
            Map<String, Set<String>> treeMap = new HashMap<>();
            int q = 0, j = 0;
            for (String key : map.keySet()) {
                j++;
                String[] keys = key.split("\\.");
                if (keys.length <= k) {
                    q++;
                    continue;
                }
                Set<String> keyList = treeMap.get(keys[k]);
                if (keyList != null) {
                    keyList.add(key);
                } else {
                    keyList = new TreeSet<>();
                    keyList.add(key);
                }
                treeMap.put(keys[k], keyList);
            }
            n.put(k, treeMap);

            if (q == j) {
                break;
            }

        }
        System.out.println(n + "------");
        Map<String, Object> linkedHashMap = new HashMap<>();
        for (int k : n.keySet()) {
            Map<String, Set<String>> setLinkedHashMap = (HashMap<String, Set<String>>) n.get(k);
            for (String key : setLinkedHashMap.keySet()) {
                Set<String> set = setLinkedHashMap.get(key);
                if (k == 0) {
                    if (set.size() == 1 && key.equals(set.iterator().next())) {
                        linkedHashMap.put(key, map.get(key));
                    } else {
                        linkedHashMap.put(key, new HashMap<>());
                    }
                } else {
                    Iterator<String> iterator = set.iterator();
                    while (iterator.hasNext()) {
                        Map<String, Object> linked = linkedHashMap;
                        String value = iterator.next();
                        String[] ele = value.split("\\.");
                        int x = k;
                        while (k - x < k) {
                            if (linked.get(ele[k - x]) == null) {
                                linked = new HashMap<>();
                            } else {
                                linked = (HashMap<String, Object>) linked.get(ele[k - x]);
                            }
                            x--;
                        }
                        if (key.equals(ele[k]) && k == ele.length - 1) {
                            linked.put(key, map.get(value));
                        } else {
                            linked.put(key, new HashMap<>());
                        }

                        x = k;
                        for (int i = 0; i < k; i++) {

                            Map<String, Object> link = linkedHashMap;
                            if (k == 3) {
                                System.out.println(link + ".........");
                            }

                            int q = -1;
                            while (x > 1 && x - q > 2 + i) {
                                q++;
                                System.out.println(link + "[[[[[[");
                                System.out.println(ele[q]);
                                link = (Map<String, Object>) link.get(ele[q].trim());
                                if (k == 3) {
                                    System.out.println(link + "----");
                                }
                            }
                            if (k == 3) {
                                System.out.println(linked + "ooooo" + ele[k - i - 1]);
                            }
                            link.put(ele[k - i - 1], linked);

                            if (k == 3) {
                                System.out.println(link + "+++++");
                            }

                            linked = link;
                        }
                        linkedHashMap = linked;
                    }
                }


            }


        }
        System.out.println(yaml.dumpAsMap(linkedHashMap));
        return yaml.dumpAsMap(linkedHashMap);
    }

    public static boolean isCmdRule(String... args) {
        for (int i = 0; i < args.length; i++){
            if (StringUtils.isBlank(args[i])) {
                String[] fbsArr = { "\\","$","(",")","*","&","../","+",".","[", "]","?",";","^","{","}","|","||","'","%" };
                for (String key : fbsArr) {
                    if (args[i].contains(key)) {
                        return false;
                    }
                }
            }

        }
        return true;
    }


    /**
     * zip解压
     * @param srcFile        zip源文件
     * @param destDirPath     解压后的目标文件夹
     * @throws RuntimeException 解压失败会抛出运行时异常
     */
    public static void unZip(File srcFile, String destDirPath) throws RuntimeException {
        long start = System.currentTimeMillis();
        // 判断源文件是否存在
        if (!srcFile.exists()) {
            throw new RuntimeException(srcFile.getPath() + "所指文件不存在");
        }
        // 开始解压
        ZipFile zipFile = null;
        try {
            zipFile = new ZipFile(srcFile);
            Enumeration<?> entries = zipFile.entries();
            while (entries.hasMoreElements()) {
                ZipEntry entry = (ZipEntry) entries.nextElement();
                // 如果是文件夹，就创建个文件夹
                if (entry.isDirectory()) {
                    String dirPath = destDirPath + "/" + entry.getName();
                    File dir = new File(dirPath);
                    dir.mkdirs();
                } else {
                    // 如果是文件，就先创建一个文件，然后用io流把内容copy过去
                    File targetFile = new File(destDirPath + "/" + entry.getName());
                    // 保证这个文件的父文件夹必须要存在
                    if(!targetFile.getParentFile().exists()){
                        targetFile.getParentFile().mkdirs();
                    }
                    targetFile.createNewFile();
                    // 将压缩文件内容写入到这个文件中
                    InputStream is = zipFile.getInputStream(entry);
                    FileOutputStream fos = new FileOutputStream(targetFile);
                    int len;
                    byte[] buf = new byte[BUFFER_SIZE];
                    while ((len = is.read(buf)) != -1) {
                        fos.write(buf, 0, len);
                    }
                    // 关流顺序，先打开的后关闭
                    fos.close();
                    is.close();
                }
            }
            long end = System.currentTimeMillis();
            System.out.println("解压完成，耗时：" + (end - start) +" ms");
        } catch (Exception e) {
            throw new RuntimeException("unzip error from ZipUtils", e);
        } finally {
            if(zipFile != null){
                try {
                    zipFile.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static String readString3(String path)
    {
        String str="";
        File file=new File(path);
        try {
            FileInputStream in=new FileInputStream(file);
            // size  为字串的长度 ，这里一次性读完
            int size=in.available();
            byte[] buffer=new byte[size];
            in.read(buffer);
            in.close();
            str=new String(buffer,"GB2312");
        } catch (IOException e) {
            // TODO Auto-generated catch block
            return null;
        }
        return str;
    }

    public static void delTempChild(File file){
        if (file.isDirectory()) {
           String[] children = file.list();
            for (int i=0; i<children.length; i++) {
            delTempChild(new File(file, children[i]));
             }
        }
        file.delete();
    }

    /**
     * 版本号比较
     *
     * @param v1
     * @param v2
     * @return 0代表相等，1代表左边大，-1代表右边大
     * Utils.compareVersion("1.0.358_20180820090554","1.0.358_20180820090553")=1
     */
    public static int compareVersion(String v1, String v2) {
        try{
            if(v1.contains("SNAPSHOT")||v2.contains("SNAPSHOT")){
                return 0;
            }
            if (v1.equals(v2)) {
                return 0;
            }
            String[] version1Array = v1.split("[._]");
            String[] version2Array = v2.split("[._]");
            int index = 0;
            int minLen = Math.min(version1Array.length, version2Array.length);
            long diff = 0;
            while (index < minLen
                    && (diff = Long.parseLong(version1Array[index])
                    - Long.parseLong(version2Array[index])) == 0) {
                index++;
            }
            if (diff == 0) {
                for (int i = index; i < version1Array.length; i++) {
                    if (Long.parseLong(version1Array[i]) > 0) {
                        return 1;
                    }
                }
                for (int i = index; i < version2Array.length; i++) {
                    if (Long.parseLong(version2Array[i]) > 0) {
                        return -1;
                    }
                }
                return 0;
            } else {
                return diff > 0 ? 1 : -1;
            }
        }catch (Exception e){
            logger.error("版本号格式解析失败，版本号不符合规范:{}",e.getMessage());
            return -1;
        }
    }

    public static boolean checkName(String name){
        logger.info("检测的文件路径{}",name);
        String sts="~,!,@,#,$,%,^,&,*,+,|,},{,\",:,<,>,?,;,\',\',\\,=,`,。";
        String[] arrays=sts.split(",");
        boolean flag=false;
        for(int i=0;i<arrays.length;i++){
            flag=name.contains(arrays[i]);
            if(flag){
                break;
            }
        }
        return flag;
    }

    /**
     * 判断密码是否符合强度规则
     * 密码中必须包含字母、数字、特称字符，至少8个字符，最多30个字符。
     * @param pwd 密码
     * @return
     */
    public static boolean chechPwd(String pwd){
        String str = "(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[^a-zA-Z0-9]).{8,30}";
        return Pattern.matches(str, pwd);
    }


    /**
     * 将输入流写入文件
     * @param stream
     * @param filePath
     * @param fileName
     * @return
     */
    public static boolean writeFile(InputStream stream,String filePath, String fileName){
        try {
            if(!new File(filePath).exists()){
                new File(filePath).mkdirs();
            }
            Files.copy(stream, Paths.get(fullPath(filePath,fileName)));
            File file = new File(fullPath(filePath,fileName));
        }catch (Exception e){
            return false;
        }
        return true;
    }

    public static List<File> searchFiles(File folder, final String keyword) {
        List<File> result = new ArrayList<File>();
        if (folder.isFile())
            result.add(folder);
        File[] subFolders = folder.listFiles(new FileFilter() {
            @Override
            public boolean accept(File file) {
                if (file.isDirectory()) {
                    return true;
                }
                if (file.getName().toLowerCase().contains(keyword)) {
                    log.info("查询到的配置文件:{}",file.getAbsolutePath());
                    return true;
                }
                return false;
            }
        });

        if (subFolders != null) {
            for (File file : subFolders) {
                if (file.isFile()) {
                    // 如果是文件则将文件添加到结果列表中
                    result.add(file);
                } else {
                    // 如果是文件夹，则递归调用本方法，然后把所有的文件加到结果列表中
                    result.addAll(searchFiles(file, keyword));
                }
            }
        }

        return result;
    }







}
